#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include "lockGuard.hpp"

const int defaultcap = 5;

template<class T>
class blockqueue
{
public:
    blockqueue(int cap = defaultcap):_capacity(cap)
    {
        pthread_mutex_init(&_mutex, NULL);
        pthread_cond_init(&_c_cond, NULL);
        pthread_cond_init(&_p_cond, NULL);
    }
    bool isfull()
    {
        return bq.size() == _capacity;
    }
    bool isempty()
    {
        return bq.size() == 0;
    }
    void push(const T& in)
    {
        lockguard lg(&_mutex);
        while(isfull()){
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        bq.push(in);
        pthread_cond_signal(&_c_cond);
    }
    void pop(T* out)
    {
        lockguard lg(&_mutex);
        while(isempty()){
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        *out = bq.front();
        bq.pop();
        pthread_cond_signal(&_p_cond);
    }
    ~blockqueue()
    {
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
        pthread_mutex_destroy(&_mutex);
    }
private:
    int _capacity; // _q.size() == _capacity, 满了，不能在生产，_q.size() == 0, 空，不能消费了
    std::queue<T>  bq;
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
};